<?php
/**
 * 签名验证模块
 * 
 * @author jlpay-sdk-php
 * @version 1.0.0
 */

namespace JLPay\Core;

use Exception;
use JLPay\Utils\SmUtils;

/**
 * 签名验证异常类
 */
class SignVerifyException extends Exception
{
    //
}

/**
 * 签名验证类
 */
class SignVerifier
{
    /**
     * 配置对象
     * 
     * @var mixed
     */
    private $config;
    
    /**
     * 初始化签名验证类
     * 
     * @param mixed $config 配置对象实例
     */
    public function __construct($config)
    {
        $this->config = $config;
    }
    
    /**
     * 生成请求签名
     * 
     * @param string $method HTTP请求方法
     * @param string $uri 请求URI
     * @param mixed $body 请求体
     * @return array 签名信息数组 [签名值, 时间戳, 随机字符串]
     * @throws Exception
     */
    public function sign($method, $uri, $body)
    {
        // 生成时间戳和随机字符串
        $timestamp = (string)time();
        $randomString = SmUtils::generateRandomString(32);
        
        // 构建签名内容
        $bodyStr = is_array($body) || is_object($body) 
            ? json_encode($body, JSON_UNESCAPED_UNICODE) 
            : (string)$body;
        
        $signBody = "{$method}\n{$uri}\n{$timestamp}\n{$randomString}\n{$bodyStr}\n";
        
        // 进行签名
        $signValue = SmUtils::sm2Sign(
            $signBody, 
            $this->config->orgPriKeyHex, 
            $this->config->orgPubKeyHex
        );
        
        return [$signValue, $timestamp, $randomString];
    }
    
    /**
     * 验证响应签名
     * 
     * @param string $method HTTP请求方法
     * @param string $uri 请求URI
     * @param string $timestamp 时间戳
     * @param string $nonce 随机字符串
     * @param string $body 响应体
     * @param string $signature 签名值
     * @return bool 验证结果，true或false
     * @throws SignVerifyException 验签失败时抛出
     */
    public function verify($method, $uri, $timestamp, $nonce, $body, $signature)
    {
        // 构建签名内容
        $signBody = "{$method}\n{$uri}\n{$timestamp}\n{$nonce}\n{$body}\n";
        
        // 验证签名
        $verifyResult = SmUtils::sm2Verify(
            $signBody, 
            $signature, 
            $this->config->jlpayPubKeyHex
        );
        
        if (!$verifyResult) {
            throw new SignVerifyException("响应签名验证失败");
        }
        
        return true;
    }
}

/**
 * 签名管理器
 */
class SignVerifierManager
{
    /**
     * 获取签名验证器
     * 
     * @param mixed $config 配置对象实例
     * @return SignVerifier SignVerifier实例
     */
    public static function getVerifier($config)
    {
        return new SignVerifier($config);
    }
} 